package com.bryanprogramming.zend.gui;

import com.bryanprogramming.zend.gui.drawables.ClickableTile;
import com.bryanprogramming.zend.gui.drawables.Drawable;
import com.bryanprogramming.zend.logic.ZEnd;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import javax.swing.JPanel;

/**
 *
 * @author charlesbryan
 */
public class Board extends JPanel implements PropertyChangeListener, MouseListener, MouseMotionListener {

    private final Font FONT = new Font("San-Serif", Font.BOLD, 24);

    private int x = 15, y = 15;
    private final int TILE_SIZE = 80;
    private final int SPACING = 10;
    private final int ARC_SIZE = 15;

    private ArrayList<Point> makeWordList = new ArrayList<>();

    private ArrayList<Drawable> drawableTiles;
    private ClickableTile[][] tiles = new ClickableTile[4][4];

    Board() {
        this(true);
    }

    Board(boolean test) {
        this.addMouseMotionListener(this);
        this.addMouseListener(this);

        drawableTiles = new ArrayList<>();

        int size = TILE_SIZE * 4 + x + y + 3 * SPACING;
        this.setPreferredSize(new Dimension(size, size));
        x = y = 15;
        for (int row = 0; row < tiles.length; row++) {
            for (int col = 0; col < tiles[row].length; col++) {

                ClickableTile current = new ClickableTile(
                        new RoundRectangle2D.Double(x, y, TILE_SIZE, TILE_SIZE, ARC_SIZE, ARC_SIZE));
                drawableTiles.add(current);
                tiles[row][col] = current;

                x += TILE_SIZE + SPACING;
            }
            x = 15;
            y += TILE_SIZE + 7;
        }

    }
    
    public void reset() {
        for(ClickableTile[] tileRow : tiles) {
            for(ClickableTile tile : tileRow) {
                tile.reset();
            }
        }
        makeWordList.clear();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        g.setFont(FONT);

        for (Drawable d : drawableTiles) {
            d.draw(g);
        }

    }

    void setBoard(char[][] letters) {
        for (int row = 0; row < letters.length; row++) {
            for (int col = 0; col < letters[row].length; col++) {
                tiles[row][col].setValue(letters[row][col]);
            }
        }
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        {
            if (evt.getPropertyName().equals(ZEnd.Properties.BOARD_CHANGED)) {
                setBoard((char[][]) evt.getNewValue());
            }
            else if (evt.getPropertyName().equals(ZEnd.Properties.NEW_TILE)) {
                ZEnd.Tile tile = (ZEnd.Tile) evt.getNewValue();
                tiles[tile.getRow()][tile.getCol()].setValue(tile.getValue());
                tiles[tile.getRow()][tile.getCol()].animateGrow();
            }
        }
    }

    private void setMouseOver(Point e) {
        for (int row = 0; row < tiles.length; row++) {
            for (int col = 0; col < tiles[row].length; col++) {
                tiles[row][col].setMouseOver(tiles[row][col].isMouseOver(e));
            }
        }
    }

    private void setMousePressed(Point e, boolean pressed) {
        for (int row = 0; row < tiles.length; row++) {
            for (int col = 0; col < tiles[row].length; col++) {
                tiles[row][col].setPressed(tiles[row][col].isMouseOver(e) && pressed);
            }
        }
    }

    private void setMouseClicked(Point e) {
        for (int row = 0; row < tiles.length; row++) {
            for (int col = 0; col < tiles[row].length; col++) {
                if (tiles[row][col].isMouseOver(e)) {
                    makeWordList.add(new Point(row, col));
                    tiles[row][col].setClicked(true);
                }
            }
        }
    }

    private final ScheduledExecutorService scheduler
            = Executors.newScheduledThreadPool(1);
    private ScheduledFuture<?> feederHandle;

    void startDrawing() {
        final Runnable feeder = new Runnable() {
            @Override
            public void run() {
                repaint();
            }
        };
        feederHandle = scheduler.scheduleAtFixedRate(feeder, 0, 5, MILLISECONDS);
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        setMouseClicked(e.getPoint());
    }

    @Override
    public void mousePressed(MouseEvent e) {
        setMousePressed(e.getPoint(), true);
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        setMousePressed(e.getPoint(), false);
    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }

    @Override
    public void mouseDragged(MouseEvent e) {

    }

    @Override
    public void mouseMoved(MouseEvent e) {
        setMouseOver(e.getPoint());
    }

    /**
     * @param inWordMode the inWordMode to set
     */
    public void setInWordMode(boolean inWordMode) {
        makeWordList.clear();
        for (ClickableTile[] tileRow : tiles) {
            for (ClickableTile tile : tileRow) {
                tile.setClickable(inWordMode);
            }
        }
        clearClickedTiles();
    }

    public Point[] getWordList() {
        Point[] pArray = new Point[makeWordList.size()];
        makeWordList.toArray(pArray);
        return pArray;
    }
    
    private void clearClickedTiles() {
       for (ClickableTile[] tileRow : tiles) {
            for (ClickableTile tile : tileRow) {
                tile.setClicked(false);
            }
        }        
    }

}
